package com.haoma.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.haoma.dto.LikeDto;
import com.haoma.dto.TalkDto;
import com.haoma.dto.UrlDto;
import com.haoma.entity.*;
import com.haoma.exception.BlogException;
import com.haoma.mapper.*;
import com.haoma.minio.MinIOConfig;
import com.haoma.minio.MinIOConfigProperties;
import com.haoma.service.TalkService;
import com.haoma.vo.*;
import io.minio.BucketExistsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Description:
 */
@Service
public class TalkServiceImpl extends ServiceImpl<TalkAdminMapper, Talk> implements TalkService {

    @Autowired
    private TalkUserMapper talkUserMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private TalkAdminMapper talkAdminMapper;

    @Autowired
    private TalkCommentMapper talkCommentMapper;

    @Autowired
    private TalkCommentRelationMapper talkCommentRelationMapper;

    @Autowired
    private UserCommentRelationMapper userCommentRelationMapper;

    @Autowired
    private TalkImageMapper talkImageMapper;

    @Autowired
    private TalkUrlRelationMapper talkUrlRelationMapper;

    @Autowired
    private MinIOConfig minIOConfig;

    @Autowired
    private MinIOConfigProperties minIOConfigProperties;


    /**
     * 获取所有说说
     *
     * @return
     */
    public List<AllTalkVo> getTalkList(Integer status) {
        // 查询全部的数据
        List<TalkVo> talkVoList = talkAdminMapper.getTalkList(status);

        // 将说说的信息提取出来
        Set<Talk> talkSet = talkVoList.stream()
                .map(talkVo -> {
                    // 封装说说的基本信息
                    Talk talk = new Talk();
                    talk.setCommentCount(talkVo.getCommentCount());
                    talk.setContent(talkVo.getContent());
                    talk.setLikeCount(talkVo.getLikeCount());
                    talk.setCreateTime(talkVo.getTCreateTime());
                    talk.setId(talkVo.getId());
                    return talk;
                }).collect(Collectors.toSet());

        // 封装返回数据
        List<AllTalkVo> allTalkVoList = new ArrayList<>();

        // 获取所有的用户
        List<TalkUser> talkUserList = talkUserMapper
                .selectList(new LambdaQueryWrapper<TalkUser>()
                        .orderByDesc(TalkUser::getCreateTime));

        // 遍历说说
        for (Talk talk : talkSet) {
            // 封装所有的评论
            Set<CommentVo> commentVoSet = new HashSet<>();
            // 存储返回数据
            AllTalkVo allTalkVo = new AllTalkVo();
            // 将基本信息存储
            allTalkVo.setTalk(talk);
            // 存储图片数据
            Set<String> stringList = new HashSet<>();
            // 存储当前数据
            List<LikeDto> likeDtoList = new ArrayList<>();
            // 处理图片用的
            Map<Integer, Set<String>> map = new HashMap<>();
            // 遍历用户
            for (TalkUser talkUser : talkUserList) {
                // 从redis中查询
                Object o = redisTemplate.opsForHash().get("talk" + talk.getId(), talkUser.getId());
                if (o == null) {
                    break;
                }
                LikeDto bean = JSONUtil.toBean(o.toString(), LikeDto.class);
                if (bean.getUrl().equals(talkUser.getAvatar()) && bean.getIsLiked()) {
                    // 有就存储
                    likeDtoList.add(bean);
                }
            }
            // 遍历全部的数据
            for (TalkVo talkVo : talkVoList) {
                // 判断
                if (talk.getId() == talkVo.getId()) {
                    if (talkVo.getIsDeleted() != null) {
                        if (talkVo.getIsDeleted() == 0) {
                            // 封装评论数据
                            CommentVo commentVo = new CommentVo();
                            commentVo.setComment(talkVo.getComment());
                            commentVo.setTcCreateTime(talkVo.getTcCreateTime());
                            commentVo.setUserUrl(talkVo.getUserUrl());
                            commentVo.setName(talkVo.getName());
                            commentVo.setId(talkVo.getCommentId());
                            commentVoSet.add(commentVo);
                        }
                    }
                    // 存储图片路径
                    stringList.add(talkVo.getUrl());
                    // 去重
                    map.put(talkVo.getId(), stringList);
                }
            }
            // 存储所有的评论
            List<CommentVo> commentVos = new ArrayList<>();
            if (!CollectionUtils.isEmpty(commentVoSet)) {
                commentVos = new ArrayList<>(commentVoSet);
                // 排序
                commentVos = commentVos.stream().sorted(Comparator.comparing(CommentVo::getTcCreateTime)).toList();
                // 存评论
                allTalkVo.setCommentList(commentVos);
            }
            // 获取到图片路径
            Set<String> setUrlList = map.entrySet().iterator().next().getValue();
            // 存储图片
            allTalkVo.setUrlList(setUrlList);
            // 存储图片路径
            allTalkVo.setTalkUserList(likeDtoList);
            // 存储整个对象
            allTalkVoList.add(allTalkVo);
        }
        // 排序
        List<AllTalkVo> sortedAllTalkVoList = allTalkVoList.stream()
                .sorted(Comparator.comparingInt((AllTalkVo item) -> item.getTalk().getId()).reversed())
                .collect(Collectors.toList());
        return sortedAllTalkVoList;
    }

    /**
     * 隐藏说说
     *
     * @param id
     */
    public void concealTalk(Integer id, Integer status) {
        // 查询该说说
        LambdaQueryWrapper<Talk> talkLambdaQueryWrapper = new LambdaQueryWrapper<>();
        talkLambdaQueryWrapper.eq(Talk::getId, id);
        Talk talk = talkAdminMapper.selectOne(talkLambdaQueryWrapper);
        if (talk == null) {
            throw new BlogException("隐藏失败");
        }
        talk.setStatus(status);
        talkAdminMapper.updateById(talk);
    }

    /**
     * 删除评论
     *
     * @param id
     * @param talkId
     */
    public void delComment(Integer id, Integer talkId) {
        // 删除评论数据
        LambdaQueryWrapper<TalkComment> talkCommentLambdaQueryWrapper = new LambdaQueryWrapper<>();
        talkCommentLambdaQueryWrapper.eq(TalkComment::getId, id);
        talkCommentMapper.delete(talkCommentLambdaQueryWrapper);
        // 删除说说评论关系表
        LambdaQueryWrapper<TalkCommentRelation> talkCommentRelationLambdaQueryWrapper = new LambdaQueryWrapper<>();
        talkCommentRelationLambdaQueryWrapper.eq(TalkCommentRelation::getCommentId, id);
        talkCommentRelationLambdaQueryWrapper.eq(TalkCommentRelation::getTalkId, talkId);
        talkCommentRelationMapper.delete(talkCommentRelationLambdaQueryWrapper);
        // 删除用户评论关系表的数据
        LambdaQueryWrapper<UserCommentRelation> userCommentRelationLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userCommentRelationLambdaQueryWrapper.eq(UserCommentRelation::getCommentId, id);
        userCommentRelationMapper.delete(userCommentRelationLambdaQueryWrapper);
    }

    /**
     * 发布说说
     *
     * @param talkDto
     */
    @Transactional
    public void sendTalk(TalkDto talkDto) {
        Talk talk = new Talk();
        talk.setContent(talkDto.getContent());
        talk.setStatus(talkDto.getStatus());
        talkAdminMapper.insert(talk);

        for (UrlDto urlDto : talkDto.getFileList()) {
            TalkImage talkImage = new TalkImage();
            talkImage.setUrl(urlDto.getUrl());
            talkImageMapper.insert(talkImage);
            // 插入到用户图片关系表中
            TalkUrlRelation talkUrlRelation = new TalkUrlRelation();
            talkUrlRelation.setTalkId(talk.getId());
            talkUrlRelation.setUrlId(talkImage.getId());
            talkUrlRelationMapper.insert(talkUrlRelation);
        }
    }

    /**
     * 上传说说图片
     *
     * @param multipartFile
     * @return
     */
    public String fileUpload(MultipartFile multipartFile) {
        try {
            // 连接客户端
            MinioClient minioClient = minIOConfig.buildMinioClient();
            // 判断桶是否存在
            boolean isBucket = minioClient.bucketExists(BucketExistsArgs.builder().bucket(minIOConfigProperties.getBucket()).build());
            if (!isBucket) {
                // 不存在创建一个
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(minIOConfigProperties.getBucket()).build());
            } else {
                // 提示程序员存在
                System.out.println("Bucket 'test' already exists.");
            }
            // 设置存储路径
            // 当天作为目录
            String date = DateUtil.format(new Date(), "yyyyMMdd");
            // 唯一id作为图片路径
            String uuid = UUID.randomUUID().toString().replace("-", "");
            // 组合＋业务
            String fileName = "admin-talkuser" + "/" + date + "/" + uuid + multipartFile.getOriginalFilename();
            System.out.println(fileName);

            // 构建上传参数
            PutObjectArgs putObjectArgs = PutObjectArgs.builder()
                    .bucket(minIOConfigProperties.getBucket())
                    .stream(multipartFile.getInputStream(), multipartFile.getSize(), -1)
                    .object(fileName)
                    .build();
            // 上传
            minioClient.putObject(putObjectArgs);
            return minIOConfigProperties.getReadPath() + "/" + minIOConfigProperties.getBucket() + "/" + fileName;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 修改说说
     *
     * @param id
     * @param talkDto
     */
    @Transactional
    public void updateTalk(Integer id, TalkDto talkDto) {
        LambdaQueryWrapper<Talk> talkLambdaQueryWrapper = new LambdaQueryWrapper<>();
        talkLambdaQueryWrapper.eq(Talk::getId, id);
        Talk talkDb = talkAdminMapper.selectOne(talkLambdaQueryWrapper);
        talkDb.setContent(talkDto.getContent());
        talkDb.setStatus(talkDto.getStatus());
        talkAdminMapper.updateById(talkDb);

        for (UrlDto urlDto : talkDto.getFileList()) {
            // 先查
            LambdaQueryWrapper<TalkImage> talkImageLambdaQueryWrapper = new LambdaQueryWrapper<>();
            talkImageLambdaQueryWrapper.eq(TalkImage::getUrl, urlDto.getUrl());
            TalkImage talkImageDb = talkImageMapper.selectOne(talkImageLambdaQueryWrapper);

            // 没有那就插入
            TalkImage talkImage = new TalkImage();
            // 判断是否有
            if (talkImageDb == null) {
                talkImage.setUrl(urlDto.getUrl());
                talkImageMapper.insert(talkImage);
                // 插入
                TalkUrlRelation talkUrlRelation = new TalkUrlRelation();
                talkUrlRelation.setTalkId(talkDb.getId());
                talkUrlRelation.setUrlId(talkImage.getId());
                talkUrlRelationMapper.insert(talkUrlRelation);
            } else {
                // 有就修改
                talkImageDb.setUrl(talkImage.getUrl());
                talkImageMapper.updateById(talkImageDb);
            }
        }
    }

    /**
     * 根据id删除说说
     *
     * @param id
     */
    public void delTalk(Integer id) {
        // 先查询说说
        LambdaQueryWrapper<Talk> talkLambdaQueryWrapper = new LambdaQueryWrapper<>();
        talkLambdaQueryWrapper.eq(Talk::getId, id);
        Talk talk = talkAdminMapper.selectOne(talkLambdaQueryWrapper);

        // 判断
        if (talk == null) {
            throw new BlogException("删除失败!");
        }

        // 开始删除
        talkAdminMapper.delete(talkLambdaQueryWrapper);
    }

    /**
     * 分页查询用户
     *
     * @param page
     * @param limit
     * @param name
     * @return
     */
    public TalkPageVo getUserList(Long page, Long limit, String name) {
        // 设置分页参数
        Page<TalkUser> talkUserPage = new Page<>(page, limit);

        // 设置条件
        LambdaQueryWrapper<TalkUser> talkUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
        talkUserLambdaQueryWrapper.orderByDesc(TalkUser::getCreateTime);

        // 判断
        if (name != null) {
            talkUserLambdaQueryWrapper.like(TalkUser::getUserName, name);
        }

        // 开始查询
        Page<TalkUser> talkUserPage1 = talkUserMapper.selectPage(talkUserPage, talkUserLambdaQueryWrapper);

        // 查询所有的说说
        LambdaQueryWrapper<Talk> talkLambdaQueryWrapper = new LambdaQueryWrapper<>();
        talkLambdaQueryWrapper.eq(Talk::getStatus, 0);
        List<Talk> talks = talkAdminMapper.selectList(talkLambdaQueryWrapper);


        // 封装返回数据
        List<TalkUserVo> talkUserVoList = talkUserPage1.getRecords().stream().map(item -> {
            TalkUserVo talkUserVo = new TalkUserVo();
            talkUserVo.setUserUrl(item.getAvatar());
            talkUserVo.setName(item.getUserName());
            talkUserVo.setId(item.getId());
            talkUserVo.setCreateTime(item.getCreateTime());
            talkUserVo.setUpdateTime(item.getUpdateTime());
            // 计数点赞数量
            int likeCount = 0;
            for (Talk talk : talks) {
                // 查询该用户点赞的数量
                Object o = redisTemplate.opsForHash().get("talk" + talk.getId(), talkUserVo.getId());
                if (o != null) {
                    LikeDto bean = JSONUtil.toBean((String) o, LikeDto.class);
                    if (bean.getIsLiked()) {
                        likeCount++;
                    }
                }
            }
            talkUserVo.setLikeCount(likeCount);

            int commentCount = 0;
            // 计算评论数量
            LambdaQueryWrapper<UserCommentRelation> userCommentRelationLambdaQueryWrapper = new LambdaQueryWrapper<>();
            userCommentRelationLambdaQueryWrapper.eq(UserCommentRelation::getUserId, talkUserVo.getId());
            List<UserCommentRelation> userCommentRelations = userCommentRelationMapper.selectList(userCommentRelationLambdaQueryWrapper);
            if (!CollectionUtils.isEmpty(userCommentRelations)) {
                commentCount = userCommentRelations.size();
            }
            talkUserVo.setCommentCount(commentCount);
            return talkUserVo;
        }).toList();
        // 封装返回数据
        TalkPageVo talkPageVo = new TalkPageVo();
        talkPageVo.setRecords(talkUserVoList);
        talkPageVo.setTotal((int) talkUserPage.getTotal());
        return talkPageVo;
    }

    /**
     * 删除用户
     *
     * @param id
     */
    public void delUser(Integer id) {
        // 查询该用户下是否有评论
        LambdaQueryWrapper<UserCommentRelation> userCommentRelationLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userCommentRelationLambdaQueryWrapper.eq(UserCommentRelation::getUserId, id);
        List<UserCommentRelation> userCommentRelations = userCommentRelationMapper.selectList(userCommentRelationLambdaQueryWrapper);

        // 判断
        if (!CollectionUtils.isEmpty(userCommentRelations)) {
            throw new BlogException("该用户下还有评论!");
        }

        // 查询所有的说说
        LambdaQueryWrapper<Talk> talkLambdaQueryWrapper = new LambdaQueryWrapper<>();
        talkLambdaQueryWrapper.eq(Talk::getStatus, 0);
        List<Talk> talks = talkAdminMapper.selectList(talkLambdaQueryWrapper);

        // 遍历查询redis
        for (Talk talk : talks) {
            // 查询点赞
            Object o = redisTemplate.opsForHash().get("talk" + talk.getId(), id);
            if (o != null) {
                throw new BlogException("该用户下还有点赞!");
            }
        }

        // 可以删除
        LambdaQueryWrapper<TalkUser> talkUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
        talkUserLambdaQueryWrapper.eq(TalkUser::getId, id);
        talkUserMapper.delete(talkUserLambdaQueryWrapper);
    }
}
